home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Snippets / MultiWin TE⁄Undo⁄S_H 1.0.1 / Modeless Show_help.c next >
Encoding:
C/C++ Source or Header  |  1995-09-16  |  41.0 KB  |  1,463 lines  |  [TEXT/KAHL]

  1. #define USE_PICTS    1        /* 1 if PICTs are to be displayed, 0 for text only */
  2. #define ONE_RESOURCE 0        /* 1 for Get1Resource, 0 for GetResource, etc. */
  3. #define COMPRESSION    1        /* compressed TEXT/styl or PICTs*/
  4. /*    #define STANDALONE    0    Modeless version needs shell    */
  5.  
  6. #define CHECKPOINTS 0
  7. #define ASSERTIONS    0
  8.  
  9. #define    PREFLIGHT_MEMORY    20000L
  10.  
  11. #define        RETURN_CHAR        0x0D
  12. #define        TILDE_CHAR        0x7E
  13. #define        ENTER_CHAR        0x03
  14. #define        ESCAPE_CHAR        0x1B
  15.  
  16. /*    #define         clikLoop        clickLoop
  17.         This is only needed for Universal Headers
  18.         I could not get this code to compile with the new headers.  I got an error
  19.         telling me "HiliteMode" was undefined.  I don't know what the deal is...    */
  20.             
  21.  
  22. /*    Modeless Show_help    1.0.1
  23.     Change: Added Toggle_S_H_Buttons() routine to dim buttons/remove default outline
  24.             or undim/re-add same on activation/deactivation of Show_help window.
  25.             Added appropriate calls in the routine: Handle_ShowHelp
  26.             Added #define    KOutlinePICT    8
  27.  
  28.     Original Show_help: by James W. Walker, June 1991    
  29.         version 2.0, updated July 1992
  30.  
  31.     Modified by Eric Long 1994-95 to save the style information in the text file
  32.     and for modeless use. This modified code is distributed by permission of James Walker.
  33.     
  34.     Unless you compare the two versions, it may not be obvious what all was done
  35.     to modify the routines.  I didn't spend a lot of time marking it out.  Various
  36.     places had to be broken apart and others rehashed, but for the most part, it all does
  37.     about the same as before, only now it is set up to be a modeless dialog.
  38.             
  39.     ------------------------------------------------------------------------------
  40.     James Walker's Comments from original Show_Help:
  41.  
  42.         This code is freely usable.  If you want to show your gratitude,
  43.     you could send me a free copy of whatever program you develop
  44.     with it.
  45.     
  46.     e-mail:
  47.         Internet            76367.2271@compuserve.com
  48.         CIS                    76367,2271
  49.         America Online        JWWalker
  50.     
  51.     This code displays scrolling text in a dialog box.  The text comes
  52.     from TEXT/styl resources, which can be created with ResEdit 2.1 or
  53.     with an accompanying HyperCard stack.
  54.     The text cannot be edited, but one can select text and copy it to
  55.     the clipboard using command-C, or save it as a TeachText file.
  56.     
  57.     Pictures can be included in the text using the same scheme as
  58.     TeachText: Each option-space character indicates where the top
  59.     edge of a picture should go, and pictures are centered horizontally.
  60.     Pictures come from consecutively-numbered PICT resources.  
  61.     
  62.     A popup menu can be used to jump to "bookmarks", which are indicated
  63.     by tab characters at ends of lines.
  64.     -------------------------------------------------------------------------
  65.     
  66. */
  67.  
  68. #if ASSERTIONS
  69.     #define    ASSERT_SET_NIL(lvalue)    lvalue = NIL
  70. #else
  71.     #define    ASSERT_SET_NIL(lvalue)
  72. #endif
  73.  
  74.     void    main( void );
  75.  
  76. #include "Modeless Show_help.h"
  77. #include "Show_help typedefs.h"
  78.  
  79.  
  80. #ifndef NIL
  81.     #define        NIL        0L
  82. #endif
  83.  
  84. #if ONE_RESOURCE
  85.     #define GetResource            Get1Resource
  86.     #define CountResources        Count1Resources
  87.     #define GetNamedResource    Get1NamedResource
  88. #endif ONE_RESOURCE
  89.  
  90. #if ASSERTIONS
  91.     #define        ASSERT(x,y)        if (!(x)) {DebugStr("\p" y);}
  92. #else
  93.     #define        ASSERT(x,y)
  94. #endif ASSERTIONS
  95.  
  96. #if CHECKPOINTS
  97.     #define CKPT(x)        DebugStr( "\p" x )
  98. #else
  99.     #define CKPT(x)
  100. #endif CHECKPOINTS
  101.  
  102. enum {
  103.     c_OK = 1,    /* OK button */
  104.     c_help,        /* userItem for our help display */
  105.     c_save,        /* Button to save as TeachText */
  106.     c_menu        /* userItem for popup menu */
  107. };
  108. #define         c_nullControl1        9    // Storage for Show_HelpInfo handle
  109. #define         KOutlinePICT            8
  110.  
  111.  
  112. #define        SCROLLBAR_WIDTH    16
  113. #define        TEXT_INSET        4
  114.  
  115. #define        INITIAL_HIGHLIGHTS        8
  116.  
  117. TEHandle    gHelp_Text;
  118.  
  119. /* Prototypes of private routines */
  120. static pascal void  Text_userItem_proc( WindowPtr the_window, short item_num );
  121. static pascal void  Menu_userItem_proc( WindowPtr the_window, short item_num );
  122. static pascal void Scroll_text( ControlHandle the_bar, short part_code );
  123. static pascal Auto_scroll( void );
  124. static void Handle_scroll( DialogPtr dialog,
  125.     short the_part, Point local_point );
  126. static void Adjust_text( DialogPtr dialog );
  127. static void Save_text( TEHandle the_text, StScrpHandle help_styl,
  128.                                         StringPtr default_filename );
  129. static void Topic_menu( DialogPtr dlog, MenuHandle help_popup );
  130. static MenuHandle Build_popup( TEHandle    the_text, StringPtr default_menuname );
  131. static short    Find_char(
  132.             Handle    data_h,        // handle to a block of characters
  133.             short    offset,        // initial offset within block
  134.             char    what );        // the character we're looking for
  135.             
  136. /* Prototypes of routines created for modeless support by Eric Long */
  137. void            Handle_ShowHelp( EventRecord *event, DialogPtr dialog );
  138. void            Close_ShowHelp(DialogPtr dptr);
  139. void            Adjust_EditMenu( Boolean do_activate, TEHandle the_text );
  140. void            Do_ShowHelp_Copy( DialogPtr showHelpDlg );
  141. void            Adjust_Menu( short menuID, short item, Boolean switchOn );
  142. static void        Toggle_SH_ScrollBar( DialogPtr dialog, short deactivate );
  143. static void        Toggle_SH_Buttons( DialogPtr dialog, short deactivate );
  144.  
  145. #if COMPRESSION
  146.     static Handle Get_compressed_resource( ResType    the_type, short the_ID );
  147.     static void Release_compressed_resource( Handle rsrc_h );
  148.     static void Dispose_compressed_data( Handle the_handle );
  149. #else
  150.     #define Get_compressed_resource            GetResource
  151.     #define Release_compressed_resource        ReleaseResource
  152.     #define    Dispose_compressed_data(x)
  153. #endif
  154.  
  155. #if USE_PICTS
  156. static void Find_pictures( DialogPtr dlog, short first_pict_id );
  157. static void Draw_picts( WindowPtr the_window, Rect *update_rect );
  158. static pascal void High_hook( Rect *high_rect );
  159. static void Do_deferred_hilites( help_ptr  hptr, Rect *update_rect );
  160. static void Push_highlight( high_info **hh, Rect *rect );
  161. static Boolean Pop_highlight( high_info **hh, Rect *rect );
  162. #endif
  163.  
  164.  
  165. /* ------------------------- Show_help --------------------------------- */
  166. void        Init_Show_help( short info_id )
  167. {
  168.     register    DialogPtr    dptr;
  169.     register    TEHandle    the_text;
  170.     short        itype, ihit;
  171.     Handle        item_h;
  172.     Rect        help_item_box, box;
  173.     Handle            help_TEXT;
  174.     StScrpHandle    help_styl;
  175.     GrafPtr        save_port;
  176.     Rect        dest, view;
  177.     ControlHandle    the_bar;
  178.     short        max_scroll, nLines;
  179.     Point        place;
  180.     MenuHandle    help_popup;
  181.     CursHandle    watch_cursor;
  182.     Show_help_info    **the_info;
  183.     StringPtr    default_menuname, default_filename;
  184.     short        which_pict;
  185.     MenuHandle    myMenu;
  186.     
  187.     /*
  188.         I'm too lazy to check for a memory error in every possible
  189.         place, so I'll just make sure there is a reasonable amount
  190.         available before starting.
  191.     */
  192.     item_h = NewHandle( PREFLIGHT_MEMORY );
  193.     if (item_h == NIL)
  194.     {
  195.         SysBeep(1);
  196.         return;
  197.     }
  198.     else
  199.         DisposHandle( item_h );
  200.  
  201.     the_info = (Show_help_info **) GetResource( 'Hlp?', info_id );
  202.     ASSERT( the_info != NIL, "Hlp? resource missing" );
  203.     HLock( (Handle) the_info );
  204.     default_filename = (**the_info).strings;
  205.     default_menuname = default_filename + default_filename[0] + 1;
  206.  
  207.     /*
  208.         Get the dialog, which has extra info tacked on the end.
  209.     */
  210.     dptr = (DialogPtr) NewPtr( sizeof(help_record) );
  211.     ASSERT( dptr != NIL, "NewPtr failed for help_record" );
  212.     dptr = GetNewDialog((**the_info).DLOG_ID, (DialogPeek) dptr, (WindowPtr)-1L );
  213.     ASSERT( dptr != NIL, "Failed GetNewDialog" );
  214.     GetPort( &save_port );
  215.     SetPort( dptr );
  216.  
  217.     
  218.     watch_cursor = GetCursor( watchCursor );
  219.     HLock( (Handle) watch_cursor );
  220.     SetCursor( *watch_cursor );
  221.     ((help_ptr) dptr)->ibeam_cursor = GetCursor( iBeamCursor );
  222.     HLock( (Handle) ((help_ptr) dptr)->ibeam_cursor );
  223.     
  224. #if USE_PICTS
  225.     ((help_ptr) dptr)->high = (high_info **) NewHandle(
  226.                 sizeof(high_info) + INITIAL_HIGHLIGHTS * sizeof(Rect) );
  227.     ASSERT( ((help_ptr) dptr)->high != NIL, "Failed to get highlight record");
  228.     (**((help_ptr) dptr)->high).array_size = INITIAL_HIGHLIGHTS;
  229.     (**((help_ptr) dptr)->high).high_waiting = 0;
  230. #endif
  231.  
  232.     help_TEXT = Get_compressed_resource( 'TEXT', (**the_info).TEXT_ID );
  233.     if (help_TEXT == NIL)
  234.     {
  235.         ASSERT(false, "Failed to find help TEXT resource" );
  236.         DisposDialog( dptr );
  237.         DisposeMenu( help_popup );
  238.         SetPort( save_port );
  239.         InitCursor();
  240.         goto getout;
  241.     }
  242.     help_styl = (StScrpHandle)
  243.         Get_compressed_resource( 'styl', (**the_info).styl_ID );
  244.     if (help_styl == NIL)
  245.     {
  246.         DisposHandle( help_TEXT );
  247.         ASSERT_SET_NIL( help_TEXT );
  248.         ASSERT( false, "Failed to find styl resource" );
  249.         DisposDialog( dptr );
  250.         DisposeMenu( help_popup );
  251.         SetPort( save_port );
  252.         goto getout;
  253.     }
  254.     HLock( help_TEXT );
  255.     
  256.     GetDItem( dptr, c_nullControl1, &itype, &item_h, &box);
  257.     SetCRefCon(item_h, (long)the_info);    // Store help info handle for later disposal
  258.  
  259.     GetDItem( dptr, c_help, &itype, &item_h, &help_item_box );
  260.     SetDItem( dptr, c_help, itype, (Handle) Text_userItem_proc, &help_item_box );
  261.     view = help_item_box;
  262.     InsetRect( &view, 1, 1 );
  263.     view.right -= SCROLLBAR_WIDTH;
  264.     dest = view;
  265.     InsetRect( &dest, TEXT_INSET, 0 );
  266.     the_text = TEStylNew( &dest, &view );
  267.     ASSERT( the_text != NIL, "Failed TEStylNew." );
  268.     
  269.     TEStylInsert( *help_TEXT, GetHandleSize(help_TEXT),
  270.         help_styl, the_text );
  271.     TEActivate( the_text );
  272.     Release_compressed_resource( help_TEXT );
  273.     ASSERT_SET_NIL( help_TEXT );
  274.     nLines = (**the_text).nLines;
  275.     gHelp_Text = the_text;    // GLOBAL POINTER USED TO STORE TEHANDLE
  276.     max_scroll = TEGetHeight( (long) nLines, 1L, the_text )
  277.         - (view.bottom - view.top);
  278.     
  279.     help_item_box.left = help_item_box.right - SCROLLBAR_WIDTH;
  280.     the_bar = NewControl( dptr, &help_item_box, "\p", true,
  281.         0, 0, max_scroll, scrollBarProc, NIL );
  282.     ASSERT( the_bar != NIL, "Failed NewControl for scroll bar." );
  283.     ((help_ptr) dptr)->scrollbar = the_bar;
  284.  
  285. #if USE_PICTS
  286.     Find_pictures( dptr, (**the_info).first_PICT_ID );
  287. #endif
  288.     help_popup = Build_popup( the_text, default_menuname );
  289.     
  290.         // Need a place to store the Handle for the popup menu - use OK button
  291.     GetDItem(dptr, c_OK, &itype, &item_h, &box);
  292.     SetCRefCon((ControlHandle)item_h, (long)help_popup);
  293.  
  294.     TEAutoView( TRUE, the_text );    /* Permit auto-scrolling */
  295.     CKPT( "Installing ClikLoop" );
  296.     (**the_text).clikLoop = (ProcPtr)Auto_scroll;
  297. #if USE_PICTS
  298.     (**the_text).highHook = (ProcPtr) High_hook;
  299.     ((help_ptr)dptr)->high_defer_flag = false;
  300. #endif
  301.  
  302.     GetDItem( dptr, c_menu, &itype, &item_h, &box );
  303.     SetDItem( dptr, c_menu, itype, (Handle) Menu_userItem_proc, &box );
  304.     
  305.     ((help_ptr)dptr)->save_clip = NewRgn();    /* Used in Draw_picts */
  306.     ASSERT( ((help_ptr)dptr)->save_clip != NIL,
  307.         "NewRgn failed for save_clip" );
  308.         
  309.         // Need a place to store the StScrpHandle for later disposal
  310.     GetDItem( dptr, c_save, &itype, &item_h, &box);
  311.     SetCRefCon(item_h, (long)help_styl);
  312.     
  313.     SetWRefCon((WindowPtr)dptr, rShowHelpDlg);    // IDENTIFY WINDOW BY DLOG ID
  314.     
  315.     if (! gWindowsOpen)
  316.         Adjust_Menu(mFile, iClose, true);
  317.     gWindowsOpen++;
  318.     
  319.     Adjust_Menu(mFile, iHelp, false);
  320.  
  321.     ShowWindow( dptr );
  322.     InitCursor();
  323.  
  324. getout:
  325.     ;
  326. }
  327.  
  328.  
  329. #if USE_PICTS
  330. /*    ----------------------------------------------------------------
  331.     High_hook            The highHook routine documented in IM IV
  332.                         (I think) expects the address of a Rect on
  333.                         top of the stack, and the return address
  334.     next on the stack.  This is opposite from the Pascal or C calling
  335.     protocol, so we have to use assembly language to swap those items.
  336.  
  337.     This deferred highlighting scheme is used to ensure that highlighting
  338.     will be done after any pictures have been drawn, not before.  To do
  339.     otherwise can cause pictures to be incorrectly highlighted during
  340.     auto-scrolling.  This error can be seen in TeachText.
  341.     ----------------------------------------------------------------
  342. */
  343. static pascal void High_hook( Rect *the_rect )
  344. {
  345.     register help_ptr    front;
  346.     
  347.     asm {
  348.         moveM.L        4(A6), A0/A1    ; load Rect address, return address
  349.         EXG.L        A0, A1            ; swap
  350.         moveM.L        A0/A1, 4(A6)    ; store return address, Rect address
  351.     }
  352.     CKPT( "High_hook");
  353.     front = (help_ptr) FrontWindow();
  354.     if ( (front != NIL) &&
  355.         (GetPtrSize((Ptr)front) == sizeof(help_record)) &&
  356.         !EmptyRect( the_rect ) )
  357.     {
  358.         if (!front->high_defer_flag)
  359.         {
  360.             HiliteMode &= ~(1 << hiliteBit);
  361.             InvertRect( the_rect );
  362.         }
  363.         else
  364.         {
  365.             Push_highlight( front->high, the_rect );
  366.         }
  367.     }
  368. }
  369.  
  370. /*    ---------------------------------------------------------------------
  371.     Push_highlight            Push a deferred highlight on the stack.
  372.                             Previously, the stack was a fixed size, because
  373.                             there never seemed to be more than 3 deferred
  374.     highlights at a time.  But then it turned out that under the Japanese
  375.     system software, there could be 7 highlights, even with the same
  376.     English text.  So now the stack can grow.
  377.     ---------------------------------------------------------------------
  378. */
  379. static void Push_highlight( high_info **hh, Rect *rect )
  380. {
  381.     if ( (**hh).high_waiting >= (**hh).array_size )
  382.     {
  383.         SetHandleSize( (Handle)hh, sizeof(high_info) +
  384.             (INITIAL_HIGHLIGHTS + (**hh).array_size) * sizeof(Rect) );
  385.         ASSERT( MemError() == noErr, "Can't expand highlight array" );
  386.         (**hh).array_size = ( GetHandleSize( (Handle)hh ) -
  387.                                     sizeof(high_info) ) / sizeof(Rect);
  388.     }
  389.     if ( (**hh).high_waiting < (**hh).array_size )
  390.     {
  391.         (**hh).high_rect[ (**hh).high_waiting ] = *rect;
  392.         (**hh).high_waiting++;
  393.     }
  394. }
  395.  
  396. /* --------------------------- Pop_highlight -------------------------- */
  397. static Boolean Pop_highlight( high_info **hh, Rect *rect )
  398. {
  399.     if ( (**hh).high_waiting > 0 )
  400.     {
  401.         (**hh).high_waiting--;
  402.         *rect = (**hh).high_rect[ (**hh).high_waiting ];
  403.         return true;
  404.     }
  405.     else
  406.         return false;
  407. }
  408.  
  409. /* ---------------------- Do_deferred_hilites ---------------------- */
  410. static void Do_deferred_hilites( help_ptr  hptr, Rect *update_rect )
  411. {
  412.     Rect    hilite;
  413.     
  414.     while (Pop_highlight( hptr->high, &hilite ))
  415.     {
  416.         if (SectRect( &hilite, update_rect, &hilite ))
  417.         {
  418.             HiliteMode &= ~(1 << hiliteBit);
  419.             InvertRect( &hilite );
  420.         }
  421.     }
  422.     hptr->high_defer_flag = false;
  423. }
  424. #endif USE_PICTS
  425.  
  426.  
  427. /* --------------------------- Find_char -------------------------- */
  428. /*
  429.     Find a character within a handle.  In a previous version I did this
  430.     with Munger().
  431.     
  432.     returns: the offset of the character, or -1 if not found.
  433. */
  434. static short    Find_char(
  435.             Handle    data_h,        // handle to a block of characters
  436.             short    offset,        // initial offset within block
  437.             char    what )        // the character we're looking for
  438. {
  439.     Ptr        text;
  440.     short    text_size, scan;
  441.     
  442.     text_size = (short) GetHandleSize( data_h );
  443.     text = *data_h;
  444.     for (scan = offset; (text[scan] != what) && (scan < text_size); ++scan)
  445.         ;
  446.     if (scan == text_size) // not found
  447.         scan = -1;
  448.     return scan;
  449. }
  450.  
  451. /* --------------------------- Build_popup ------------------------- */
  452. /*
  453.     Build a popup menu of the sections of the help text.  We scan for
  454.     tab characters.  The text between the tab character and the preceding
  455.     line break will be a menu item, unless it is the null string; then we
  456.     use the default menu name that was passed to Show_help.
  457. */
  458. static MenuHandle Build_popup( TEHandle    the_text, StringPtr default_menuname )
  459. {
  460.     MenuHandle            popup;
  461.     short                menu_id;
  462.     SignedByte            text_state;
  463.     Handle                text_h;    /* handle to just the text */
  464.     Str255                menu_data;
  465.     char                *text;    /* pointer to the help text */
  466.     register short        scan, line_start;
  467.     short                text_size, title_length;
  468.     
  469.     /* Find an unused menu ID */
  470.     menu_id = 1300; /* no particular reason */
  471.     while (GetMHandle(menu_id))
  472.         ++menu_id;
  473.     
  474.     popup = NewMenu( menu_id, "\p" );
  475.     ASSERT( popup != NIL, "NewMenu failed" );
  476.  
  477.     text_h = (**the_text).hText;
  478.     text_state = HGetState( text_h );
  479.     HLock( text_h );
  480.     text = *text_h;
  481.     text_size = (short) GetHandleSize( text_h );
  482.     line_start = 0;
  483.     for (scan = 0; scan < text_size; scan++ )
  484.     {
  485.         if (text[scan] == '\r')
  486.         {
  487.             line_start = scan + 1;
  488.         }
  489.         else if (text[scan] == '\t')
  490.         {
  491.             title_length = scan - line_start;
  492.             if (title_length == 0)
  493.                 BlockMove( default_menuname, menu_data, 256 );
  494.             else
  495.             {
  496.                 menu_data[0] = title_length; // note: <= 255
  497.                 BlockMove( &text[line_start], &menu_data[1], menu_data[0] );
  498.             }
  499.             /*
  500.                 AppendMenu recognizes meta-characters like slash,
  501.                 which is probably not what we want in this case.  So
  502.                 we use SetItem, which does not use meta-characters.
  503.             */
  504.             AppendMenu( popup, "\p " );
  505.             SetItem( popup, CountMItems(popup), menu_data );
  506.         }
  507.     }
  508.     
  509.     HSetState( text_h, text_state );
  510.     return popup;
  511. }
  512.  
  513. /* ------------------------- Topic_menu ------------------------ */
  514. /*
  515.     This routine is called when the menu title is clicked.
  516.     It pops up the menu and scrolls to the indicated tab character.
  517. */
  518. static void Topic_menu( DialogPtr dptr, MenuHandle menu )
  519. {
  520.     short            menu_id;
  521.     Handle            item_h;
  522.     short            itype;
  523.     Rect            box;
  524.     Point            where;
  525.     long            menu_return;
  526.     short            menu_choice;
  527.     ControlHandle    bar;
  528.     register short        i;
  529.     register TEHandle    the_text;
  530.     Handle            text_h;
  531.     register short        offset;
  532.     TextStyle        what_style;
  533.     short            line_height, font_ascent;
  534.     
  535.     if (menu == NIL) return;
  536.     InsertMenu( menu, -1 );
  537.     GetDItem( dptr, c_menu, &itype, &item_h, &box );
  538.     where.h = box.left;
  539.     where.v = box.bottom;
  540.     LocalToGlobal( &where );
  541.     HiliteMode &= ~(1 << hiliteBit);
  542.     InvertRect( &box );
  543.     menu_return = PopUpMenuSelect( menu, where.v, where.h, 0 );
  544.     HiliteMode &= ~(1 << hiliteBit);
  545.     InvertRect( &box );
  546.     if (HiWord(menu_return))    /* Something selected */
  547.     {
  548.         menu_choice = LoWord( menu_return );
  549.         bar = ((help_ptr)dptr)->scrollbar;
  550.         the_text = gHelp_Text;
  551.         text_h = (**the_text).hText;
  552.         
  553.         /* Find tab character number menu_choice */
  554.         offset = -1L;
  555.         for (i = 1; i <= menu_choice; ++i)
  556.         {
  557.             ++offset; /* so we don't find the same thing twice */
  558.             offset = Find_char( text_h, offset, '\t' );
  559.         }
  560.  
  561.         where = TEGetPoint( (short)offset, the_text );
  562.         TEGetStyle( (short)offset, &what_style, &line_height,
  563.             &font_ascent, the_text );
  564.         where.v -= line_height;    /* align to TOP of tab */
  565.         /*
  566.             Now where.v is in local coordinates.
  567.         */
  568.         where.v -= (**the_text).destRect.top;
  569.         SetCtlValue( bar,  where.v );
  570.         
  571.         Adjust_text( dptr );
  572.     }
  573.     menu_id = (**menu).menuID;
  574.     DeleteMenu( menu_id );
  575. }
  576.  
  577. /* ------------------------- Save_text ------------------------ */
  578. /*
  579.     This is called when the user clicks on the "Save as Text"
  580.     button.
  581. */
  582. static void Save_text( TEHandle the_text, StScrpHandle help_style,
  583.                                                 StringPtr default_filename )
  584. {
  585.     Point        where;
  586.     SFReply        reply;
  587.     OSErr        err;
  588.     short        data_refnum, res_refnum, old_resfile;
  589.     Handle        text_data;
  590.     StScrpHandle     styl_dataH;
  591.     SignedByte    state;
  592.     long        count;
  593.     GrafPtr        save_port;
  594.     short        save_vol;
  595. #if USE_PICTS
  596.     register short        num_picts, pict_index;
  597.     Handle        old_pict, new_pict;
  598.     help_ptr    dptr;
  599. #endif
  600.     
  601.     GetPort( &save_port );
  602.     where.h = where.v = 100;
  603.     SFPutFile( where, "\pName of text file:",
  604.         default_filename, NIL, &reply );
  605.     SetPort( save_port );
  606.  
  607.     if (reply.good)
  608.     {
  609.         old_resfile = CurResFile();
  610. #if USE_PICTS
  611.         dptr = (help_ptr) (**the_text).inPort;
  612.         num_picts = dptr->pict_count;
  613. #endif
  614.  
  615.         /*
  616.             The reason I use Create before FSDelete is that FSDelete
  617.             uses the PMSP and Create doesn't.  See TN 101.
  618.             
  619.             One reason that I use the old File Manager calls instead of
  620.             the newer "H" calls is that they involve more glue code
  621.             which adds to the size of the code resource.
  622.         */
  623.         err = Create( reply.fName, reply.vRefNum, 'ttxt', 'TEXT' );
  624.         if (err == dupFNErr)
  625.         {
  626.             (void) FSDelete( reply.fName, reply.vRefNum );
  627.             err = Create( reply.fName, reply.vRefNum, 'ttxt', 'TEXT' );
  628.         }
  629.         ASSERT( err == noErr, "\p error in Create" );
  630.         
  631.         (void) FSOpen( reply.fName, reply.vRefNum, &data_refnum );
  632.         
  633.         text_data = (**the_text).hText;
  634.         state = HGetState( text_data );
  635.         ASSERT( MemError() == noErr, "HGetState text_data error" );
  636.         HLock( text_data );
  637.         
  638.         count = GetHandleSize( text_data );
  639.         ASSERT( MemError() == noErr, "GetHandleSize text_data error" );
  640.         err = FSWrite( data_refnum, &count, *text_data );
  641.         ASSERT( err == noErr, "FSWrite error" );
  642.         err = FSClose( data_refnum );
  643.         ASSERT( err == noErr, "FSClose error" );
  644.         HSetState( text_data, state );
  645.  
  646.  
  647. /* Save Style Info / PICT Info as needed */
  648.         (void) GetVol( NIL, &save_vol );
  649.         (void) SetVol( NIL, reply.vRefNum );
  650.         CreateResFile( reply.fName );
  651.         ASSERT( ResError() == noErr, "\pCreateResFile error" );
  652.         res_refnum = OpenResFile( reply.fName );
  653.         ASSERT( ResError() == noErr, "\pOpenResFile error" );
  654.         (void) SetVol( NIL, save_vol );
  655.         
  656.         UseResFile( res_refnum );
  657.         styl_dataH = help_style;
  658.         if (! HandToHand (&styl_dataH));
  659.         {
  660.             AddResource( styl_dataH, 'styl',
  661.                 kBaseResID, "\p" );
  662.             ASSERT( ResError() == noErr, "AddResource error" );
  663.         }
  664.     
  665. #if USE_PICTS
  666.         for (pict_index = 0;
  667.             pict_index < num_picts; ++pict_index )
  668.         {
  669.             UseResFile( old_resfile );
  670.             old_pict = (Handle) dptr->pict_data[pict_index].pict;
  671.             if (old_pict == NIL)
  672.                 break;
  673.             new_pict = old_pict;
  674.             err == HandToHand( &new_pict );
  675.             ASSERT( err == noErr, "HandToHand error" );
  676.             UseResFile( res_refnum );
  677.             AddResource( new_pict, 'PICT',
  678.                 pict_index + 1000, "\p" );
  679.             ASSERT( ResError() == noErr, "AddResource error" );
  680.         }
  681. #endif    /* USE_PICTS */
  682.     
  683.         CloseResFile( res_refnum );
  684.         (void) FlushVol( NIL, reply.vRefNum );
  685.         UseResFile( old_resfile );
  686.     
  687.     }
  688. }
  689.  
  690.  
  691. /* ------------------------- Auto_scroll ----------------------------- */
  692. /*
  693.     This is a ClikLoop routine, called repeatedly by TEClick when the
  694.     mouse is down.
  695. */
  696. static pascal Auto_scroll()
  697. {
  698.     register    WindowPtr    the_display;
  699.     register    ControlHandle    the_bar;
  700.     Point                    mouse_point;
  701.     Rect                    view_rect;
  702.     register     TEHandle    the_text;
  703.     
  704.     asm {
  705.         movem.l        a1-a5/d1-d7, -(SP)
  706.     }
  707.     CKPT( "Auto_scroll");
  708.     the_display = FrontWindow();
  709.     if ( (the_display != NIL) &&
  710.         (GetPtrSize((Ptr)the_display) == sizeof(help_record)) )
  711.     {
  712.         the_text = gHelp_Text;
  713.         the_bar = ((help_ptr) the_display)->scrollbar;
  714.         
  715.         GetMouse( &mouse_point );
  716.         view_rect = (**the_text).viewRect;
  717.         if (mouse_point.v < view_rect.top)
  718.             Scroll_text( the_bar, inUpButton );
  719.         else if (mouse_point.v > view_rect.bottom)
  720.             Scroll_text( the_bar, inDownButton );
  721.     }
  722.     asm {
  723.         movem.L        (SP)+, a1-a5/d1-d7
  724.         moveQ        #1, D0
  725.     }
  726. }
  727.  
  728. #if USE_PICTS
  729. /* ------------------------- Draw_picts --------------------------------- */
  730. /*
  731.     Called by Adjust_text and Text_userItem_proc to draw pictures.
  732. */
  733. static void Draw_picts( WindowPtr the_window, Rect *update_rect )
  734. {
  735.     register TEHandle    the_text;
  736.     register short        pict_count, pict_index;
  737.     PicHandle    the_pict;
  738.     short         v_offset;
  739.     Rect        pict_loc, dummy;
  740.     
  741.     CKPT( "Draw_picts");
  742.     the_text = gHelp_Text;
  743.     v_offset = (**the_text).destRect.top - (**the_text).viewRect.top
  744.         - TEXT_INSET;
  745.     pict_count = ((help_ptr) the_window)->pict_count;
  746.     for (pict_index = 0; pict_index < pict_count; pict_index++)
  747.     {
  748.         pict_loc = ((help_ptr) the_window)->pict_data[pict_index].bounds;
  749.         OffsetRect( &pict_loc, 0, v_offset );
  750.         if (!SectRect( &pict_loc, update_rect, &dummy ))
  751.             continue;
  752.         the_pict = ((help_ptr) the_window)->pict_data[pict_index].pict;
  753.         GetClip( ((help_ptr) the_window)->save_clip );
  754.         ClipRect( update_rect );
  755.         DrawPicture( the_pict, &pict_loc );
  756.         SetClip( ((help_ptr) the_window)->save_clip );
  757.     }
  758. }
  759.  
  760. #define        OPTION_SPACE_CHAR    0xCA
  761.  
  762. /* ---------------------- Find_pictures ---------------------------- */
  763. static void Find_pictures( DialogPtr dlog, short first_pict_id )
  764. {
  765.     register TEHandle    the_text;
  766.     Handle        text_h;
  767.     SignedByte    text_state;
  768.     register short        offset;
  769.     short        num_picts;
  770.     register short        which_pict;
  771.     pict_info    *pict;
  772.     Point        place;
  773.     short        line_height, font_ascent;
  774.     TextStyle    what_style;
  775.     
  776.     CKPT( "Find_pictures");
  777.     the_text = gHelp_Text;
  778.     text_h = (**the_text).hText;
  779.     text_state = HGetState( text_h );
  780.     HLock( text_h );
  781.     
  782.     /* Count option-space characters in the text. */
  783.     offset = 0;
  784.     num_picts = 0;
  785.     offset = Find_char( text_h, offset, OPTION_SPACE_CHAR );
  786.     while ( offset >= 0 )
  787.     {
  788.         num_picts++;
  789.         offset++;
  790.         offset = Find_char( text_h, offset, OPTION_SPACE_CHAR );
  791.     }
  792.     
  793.     /* Allocate storage for an array of picture bounds. */
  794.     pict = (pict_info *) NewPtr( sizeof(pict_info) * num_picts );
  795.     ASSERT( pict != NIL, "NewPtr failed for pict_data" );
  796.     ((help_ptr)dlog)->pict_data = pict;
  797.     
  798.     /*
  799.         Initialize the picture info.  For each picture we record the
  800.         picture handle and its rectangle, in unscrolled window
  801.         coordinates.
  802.     */
  803.     offset = 0;
  804.     for (which_pict = 0; which_pict < num_picts; which_pict++)
  805.     {
  806.         pict[which_pict].pict = (PicHandle) Get_compressed_resource( 'PICT',
  807.             first_pict_id + which_pict );
  808.         if ( pict[which_pict].pict == NIL )
  809.             break;
  810.         offset = Find_char( text_h, offset, OPTION_SPACE_CHAR );
  811.         place = TEGetPoint( offset, the_text );
  812.         TEGetStyle( offset, &what_style, &line_height,
  813.             &font_ascent, the_text );
  814.         place.v -= line_height;    /* align picture with TOP of option-space */
  815.         offset++;
  816.         pict[which_pict].bounds = (**pict[which_pict].pict).picFrame;
  817.         OffsetRect( &pict[which_pict].bounds,
  818.             ( ((**the_text).destRect.right + (**the_text).destRect.left) -
  819.             (pict[which_pict].bounds.right + pict[which_pict].bounds.left)
  820.             ) / 2,
  821.             - pict[which_pict].bounds.top + place.v );
  822.     }
  823.     ((help_ptr)dlog)->pict_count = which_pict;
  824.     
  825. getout:
  826.     HSetState( text_h, text_state );
  827. }
  828. #endif /* USE_PICTS */
  829.  
  830.  
  831. /* ---------------------- Scroll_text ---------------------------- */
  832. /*
  833.     This is used as a TrackControl actionProc for scrolling, and also
  834.     called by Auto_scroll for automatic scrolling.
  835. */
  836. static pascal void Scroll_text( ControlHandle the_bar, short part_code )
  837. {
  838.     register TEHandle    the_text;
  839.     register short        delta;
  840.     register WindowPtr    the_display;
  841.     short                old_value;
  842.     short                offset, line;
  843.     Point                place;
  844.     Rect                view;
  845.     TextStyle            style;
  846.     short                line_height, font_ascent;
  847.     
  848.     CKPT( "Scroll_text");
  849.     if (part_code != 0)
  850.     {
  851.         the_display = (**the_bar).contrlOwner;
  852.         the_text = gHelp_Text;
  853.         view = (**the_text).viewRect;
  854.         place.h = view.left + TEXT_INSET;
  855.         
  856.         switch (part_code)
  857.         {
  858.             case inUpButton:
  859.                 place.v = view.top;
  860.                 /*
  861.                     If we get the offset of the left edge of the top line,
  862.                     then subtract 1, we should have an offset belonging
  863.                     to the previous line.
  864.                 */
  865.                 offset = TEGetOffset( place, the_text ) - 1;
  866.                 if (offset == -1) offset = 0;
  867.                 place = TEGetPoint( offset, the_text );
  868.                 TEGetStyle( offset, &style, &line_height, &font_ascent,
  869.                     the_text );
  870.                 delta = place.v - line_height - view.top;
  871.                 break;
  872.             case inDownButton:
  873.                 place.v = view.bottom + 2;
  874.                 offset = TEGetOffset( place, the_text );
  875.                 place = TEGetPoint( offset, the_text );
  876.                 /* Now place.v is at the baseline of the border line. */
  877.                 delta = place.v - view.bottom;
  878.                 break;
  879.             case inPageUp:
  880.                 /*
  881.                     I want top border line to remain visible, and
  882.                     the top of a line should end up at view.top.
  883.                 */
  884.                 place.v = view.top + 2;
  885.                 offset = TEGetOffset( place, the_text );
  886.                 place = TEGetPoint( offset, the_text );
  887.                 /* place.v is at the baseline of the top border line. */
  888.                 TEGetStyle( offset, &style, &line_height, &font_ascent,
  889.                     the_text );
  890.                 place.v += line_height - font_ascent;
  891.                 place.v -= view.bottom - view.top;
  892.                 offset = TEGetOffset( place, the_text );
  893.                 place = TEGetPoint( offset, the_text );
  894.                 TEGetStyle( offset, &style, &line_height, &font_ascent,
  895.                     the_text );
  896.                 delta = place.v - view.top;
  897.                 if (offset == 0)
  898.                     delta -= line_height;
  899.                 break;
  900.             case inPageDown:
  901.                 /*
  902.                     I want bottom border line to remain visible, and
  903.                     the bottom of a line should end up at view.bottom.
  904.                 */
  905.                 place.v = view.bottom - 2;
  906.                 offset = TEGetOffset( place, the_text );
  907.                 place = TEGetPoint( offset, the_text );
  908.                 /* place.v is at the baseline of the bottom border line. */
  909.                 TEGetStyle( offset, &style, &line_height, &font_ascent,
  910.                     the_text );
  911.                 place.v -= font_ascent; /* Top edge of bottom border line */
  912.                 place.v += view.bottom - view.top;
  913.                 /* We're looking at the bottom border of the next page. */
  914.                 offset = TEGetOffset( place, the_text );
  915.                 place = TEGetPoint( offset, the_text );
  916.                 TEGetStyle( offset, &style, &line_height, &font_ascent,
  917.                     the_text );
  918.                 delta =  place.v - line_height - view.bottom;
  919.                 if (offset == (**the_text).teLength)
  920.                     delta += line_height;
  921.                 break;
  922.         }
  923.         old_value = GetCtlValue( the_bar );
  924.         if ( ((delta < 0) && (old_value > 0)) ||
  925.             ((delta > 0) && (old_value < GetCtlMax(the_bar))) )
  926.         {
  927.             /*
  928.                 When this routine is called, TextEdit may have set the
  929.                 clipping region to the view rectangle, so we reset it
  930.                 here to make sure the scroll bar gets drawn.
  931.             */
  932.             GetClip( ((help_ptr) the_display)->save_clip );
  933.             ClipRect( &the_display->portRect );
  934.             SetCtlValue( the_bar, old_value + delta );
  935.             SetClip( ((help_ptr) the_display)->save_clip );
  936.         }
  937.         Adjust_text( the_display );
  938.     }
  939. }
  940.  
  941. /* ---------------------- Adjust_text ---------------------------- */
  942. /*
  943.     Called by Handle_scroll and Scroll_text to scroll the text and
  944.     pictures into sync with the scroll bar's control value.
  945. */
  946. static void Adjust_text( DialogPtr    dialog )
  947. {
  948.     register    TEHandle    the_text;
  949.     register    short    scroll_down;
  950.     short            old_scroll;
  951.     Rect            update_rect;
  952.     
  953.     CKPT( "Adjust_text");
  954.     the_text = gHelp_Text;
  955.     old_scroll = (**the_text).viewRect.top - (**the_text).destRect.top;
  956.     scroll_down = old_scroll -
  957.         GetCtlValue( ((help_ptr) dialog)->scrollbar );
  958.     if (scroll_down == 0)
  959.         return;
  960. #if USE_PICTS
  961.     ((help_ptr) dialog)->high_defer_flag = true;
  962.     //((help_ptr) dialog)->high_waiting = 0;
  963. #endif
  964.     TEScroll( 0, scroll_down, the_text );
  965. #if USE_PICTS
  966.     update_rect = (**the_text).viewRect;
  967.     if (scroll_down > 0)
  968.     {
  969.         if (scroll_down < (update_rect.bottom - update_rect.top))
  970.             update_rect.bottom = update_rect.top + scroll_down;
  971.     }
  972.     else
  973.         if (- scroll_down < (update_rect.bottom - update_rect.top))
  974.             update_rect.top = update_rect.bottom + scroll_down;
  975.     Draw_picts( dialog, &update_rect );
  976.     Do_deferred_hilites( (help_ptr) dialog, &update_rect );
  977. #endif
  978. }
  979.  
  980.  
  981. /* ---------------------- Handle_scroll ---------------------------- */
  982. /*
  983.     Called by Help_filter to handle mouseDown events in the scroll bar.
  984. */
  985. static void Handle_scroll( DialogPtr dialog, short the_part, Point where )
  986. {
  987.     register    ControlHandle the_bar;
  988.     
  989.     CKPT( "Handle_scroll"); SetPort( dialog );
  990.     the_bar = ((help_ptr) dialog)->scrollbar;
  991.     if (the_part == inThumb)
  992.     {
  993.         (void) TrackControl( the_bar, where, NIL );
  994.         Adjust_text( dialog );
  995.     }
  996.     else
  997.         (void) TrackControl( the_bar, where, (ProcPtr)Scroll_text );
  998.     
  999. }
  1000.  
  1001.  
  1002. /* ---------------------- Text_userItem_proc ------------------------- */
  1003. static pascal void  Text_userItem_proc( WindowPtr the_window, short item_num )
  1004. {
  1005.     Handle        item_h;
  1006.     Rect        item_box;
  1007.     short        item_type;
  1008.     TEHandle    the_text;
  1009.         
  1010.     CKPT( "Text_userItem_proc");
  1011.     the_text = gHelp_Text;
  1012.     item_box = (**the_text).viewRect;
  1013. #if USE_PICTS
  1014.     ((help_ptr) the_window)->high_defer_flag = true;
  1015. #endif
  1016.     TEUpdate( &item_box, the_text );
  1017.     
  1018. #if USE_PICTS
  1019.     Draw_picts( the_window, &item_box );
  1020.     Do_deferred_hilites( (help_ptr) the_window, &item_box );
  1021. #endif
  1022.  
  1023.     /*
  1024.         Get the item's rectangle, and frame it.
  1025.     */
  1026.     GetDItem( the_window, item_num, &item_type, &item_h, &item_box );
  1027.     FrameRect( &item_box );
  1028. }
  1029.  
  1030. /* ---------------------- Menu_userItem_proc ------------------------- */
  1031. static pascal void  Menu_userItem_proc( WindowPtr the_window, short item_num )
  1032. {
  1033.     Handle        item_h;
  1034.     Rect        item_box;
  1035.     short        item_type;
  1036.     
  1037.     CKPT( "Menu_UserItem_proc");
  1038.     
  1039.     /*
  1040.         Get the item's rectangle, and frame it.
  1041.     */
  1042.     GetDItem( the_window, item_num, &item_type, &item_h, &item_box );
  1043.     InsetRect(&item_box, -1, -1);
  1044.     FrameRect( &item_box );
  1045.     
  1046.     /* Draw the drop-shadow */
  1047.     MoveTo( item_box.left + 2, item_box.bottom );
  1048.     LineTo( item_box.right, item_box.bottom );
  1049.     LineTo( item_box.right, item_box.top + 2 );
  1050. }
  1051.  
  1052. /* ---------------------- Flash_button ----------------------------- */
  1053. pascal void Flash_button( DialogPtr the_dialog, short item_number )
  1054. {
  1055.     ControlHandle    item_h;
  1056.     long    time;
  1057.     short    itype;
  1058.     Rect    box;
  1059.     
  1060.     GetDItem( the_dialog, item_number, &itype, (Handle *)&item_h, &box );
  1061.     HiliteControl( item_h, inButton );
  1062.     Delay( 9L, &time );
  1063.     HiliteControl( item_h, 0 );
  1064. }
  1065.  
  1066. #if COMPRESSION
  1067. /* ---------------------- Get_compressed_resource ----------------------- */
  1068. static Handle Get_compressed_resource( ResType the_type, short the_ID )
  1069. {
  1070.     register Handle        CNVT_h;
  1071.     ParmInfo        info;
  1072.     CNVT_routine    Converter;
  1073.     
  1074.     info.srcHandle = GetResource( '4CMP', the_ID );
  1075.     CNVT_h = GetNamedResource( 'CNVT', "\p4CMPUncompress 4CMP" );
  1076.     if ( (info.srcHandle == NIL) ||    /* maybe there's an uncompressed one */
  1077.         (CNVT_h == NIL) )
  1078.     {
  1079.         info.dstHandle = GetResource( the_type, the_ID );
  1080.     }
  1081.     else    /* found a compressed resource */
  1082.     {
  1083.         info.srcType = '4CMP';
  1084.  
  1085.         HLock(CNVT_h);
  1086.         Converter = (CNVT_routine) StripAddress( *CNVT_h );
  1087.         CKPT("\pAbout to call the CNVT");
  1088.         (void) Converter( NIL, &info );
  1089.         CKPT("\pAfter the CNVT");
  1090.         HUnlock(CNVT_h);
  1091.         
  1092.         ReleaseResource( info.srcHandle );
  1093.     }
  1094.     return    info.dstHandle;
  1095. }
  1096.  
  1097. #define        mem_resource    0x20
  1098.  
  1099. /* ------------------------- Release_compressed_resource ------------- */
  1100. /*
  1101.     If it's a resource handle, release it, otherwise dispose of it.
  1102. */
  1103. static void Release_compressed_resource( Handle rsrc_h )
  1104. {
  1105.     if ( HGetState( rsrc_h ) & mem_resource )
  1106.         ReleaseResource( rsrc_h );
  1107.     else
  1108.         DisposHandle( rsrc_h );
  1109. }
  1110.  
  1111. /*    -------------------------------------------------------------------
  1112.     Dispose_compressed_data        If the handle is not a resource, hence
  1113.                                 the result of decompression, then
  1114.                                 dispose of it.  Otherwise (the case of
  1115.                                 an actual resource handle) do nothing.
  1116.     This is the what I do with PICTs, because a PICT may be doing double
  1117.     duty, say as a dialog item, and then it should not be released.
  1118.     -------------------------------------------------------------------
  1119. */
  1120. static void Dispose_compressed_data( Handle the_handle )
  1121. {
  1122.     if ( !(HGetState( the_handle ) & mem_resource) )
  1123.         DisposHandle( the_handle );
  1124. }
  1125. #endif COMPRESSION
  1126.  
  1127.  
  1128. /************************************************************************/
  1129. /*                                                                        */ 
  1130. /*            Modeless Support For Show_Help - Added By Eric Long            */
  1131. /*                                                                        */
  1132. /************************************************************************/ 
  1133.  
  1134. /************************** Handle_ShowHelp *****************************/ 
  1135.  
  1136. void    Handle_ShowHelp( EventRecord *event, DialogPtr dialog )
  1137. {
  1138.     Point                local_point;
  1139.     short                the_part;
  1140.     short                ihit;
  1141.     ControlHandle        the_control;
  1142.     MenuHandle            help_popup;
  1143.     short                charcode;
  1144.     Rect                item_box;
  1145.     short                cursor;
  1146.     WindowPtr            which_window;
  1147.     RgnHandle            gray_rgn;
  1148.     Rect                gray_rect;
  1149.     GrafPtr                oldPort;
  1150.     StScrpHandle        help_styl;
  1151.     Show_help_info        **the_info;
  1152.     StringPtr            default_filename;
  1153.     short                iType;
  1154.     WindowPeek            dWindowPeek;
  1155.     
  1156.     dWindowPeek = (WindowPeek)dialog;
  1157.     if (dWindowPeek->hilited)
  1158.     {
  1159.         GetMouse( &local_point );
  1160.         if (PtInRect( local_point, &(**gHelp_Text).viewRect ))
  1161.             SetCursor( *(((help_ptr) dialog)->ibeam_cursor) );
  1162.         else
  1163.             InitCursor();
  1164.     }
  1165.         
  1166.     TEIdle( gHelp_Text );
  1167.     
  1168.     switch (event->what) {
  1169.         case activateEvt:
  1170.             if (event->modifiers & activeFlag)
  1171.             {
  1172.                 SetPort(dialog);
  1173.                 TEActivate(gHelp_Text);
  1174.                 Toggle_SH_ScrollBar(dialog, kEnableControl);
  1175.                 Toggle_SH_Buttons(dialog, kEnableControl);
  1176.             }
  1177.             else
  1178.             {
  1179.                 TEDeactivate(gHelp_Text);
  1180.                 Toggle_SH_ScrollBar(dialog, kDisableControl);
  1181.                 Toggle_SH_Buttons(dialog, kDisableControl);
  1182.                 UpdtDialog(dialog, dialog->visRgn);
  1183.                 InitCursor();
  1184.             }
  1185.             Adjust_EditMenu(event->modifiers & activeFlag, gHelp_Text);
  1186.             break;
  1187.         case osEvt:
  1188.             if (event->message & resumeFlag)
  1189.             {
  1190.                 TEActivate(gHelp_Text);
  1191.                 Toggle_SH_ScrollBar(dialog, kEnableControl);
  1192.                 Toggle_SH_Buttons(dialog, kEnableControl);
  1193.             }
  1194.             else
  1195.             {
  1196.                 TEDeactivate(gHelp_Text);
  1197.                 Toggle_SH_ScrollBar(dialog, kDisableControl);
  1198.                 Toggle_SH_Buttons(dialog, kDisableControl);
  1199.                 InitCursor();
  1200.             }
  1201.             Adjust_EditMenu(event->modifiers & activeFlag, gHelp_Text);
  1202.             break;
  1203.         case mouseDown:
  1204.             the_part = FindWindow( event->where, &which_window );
  1205.             local_point = event->where;
  1206.             GlobalToLocal( &local_point );
  1207.             if ( (which_window == dialog) && (the_part == inContent) )
  1208.             {
  1209.                 the_part = FindControl( local_point, dialog, &the_control );
  1210.                 if (the_part && ((**the_control).contrlMax > 1) )
  1211.                 {
  1212.                     Handle_scroll( dialog, the_part, local_point );    
  1213.                     break;
  1214.                 }
  1215.                 else if (PtInRect( local_point, &(**gHelp_Text).viewRect ))
  1216.                 {
  1217.                     if (event->modifiers & shiftKey)
  1218.                         TEClick( local_point, true, gHelp_Text );
  1219.                     else
  1220.                         TEClick( local_point, false, gHelp_Text );
  1221.                         
  1222.                     if ((**gHelp_Text).selStart != (**gHelp_Text).selEnd)
  1223.                     {
  1224.                         Adjust_Menu(mEdit, 0, true);
  1225.                         Adjust_Menu(mEdit, iCopy, true);
  1226.                     }
  1227.                     else
  1228.                     {
  1229.                         Adjust_Menu(mEdit, 0, false);
  1230.                         Adjust_Menu(mEdit, iCopy, false);
  1231.                     }
  1232.                     DrawMenuBar();
  1233.                 }
  1234.                 else    // Handle Clicks in Buttons
  1235.                 {
  1236.                     ihit = FindDItem(dialog, local_point) +1;
  1237.                     if (ihit == c_save)
  1238.                     {
  1239.                         if ( TrackControl(the_control, event->where, nil) != 0 )
  1240.                         {
  1241.                             help_styl = (StScrpHandle)(GetCRefCon(the_control));
  1242.                             
  1243.                             GetDItem(dialog, c_nullControl1, &iType, &the_control, &item_box);
  1244.                             the_info = (Show_help_info **)GetCRefCon(the_control);
  1245.                             HLock( (Handle) the_info );
  1246.                             default_filename = (**the_info).strings;
  1247.                             HUnlock( (Handle) the_info );
  1248.                             
  1249.                             Save_text( gHelp_Text, help_styl, default_filename );
  1250.                         }
  1251.                     }
  1252.                     else if (ihit == c_menu)
  1253.                     {
  1254.                         GetDItem(dialog, c_OK, &iType, &the_control, &item_box);
  1255.                         help_popup = (MenuHandle)(GetCRefCon(the_control));
  1256.                         Topic_menu( dialog, help_popup );
  1257.                     }
  1258.                     else
  1259.                     {
  1260.                         if (ihit == c_OK)
  1261.                             if ( TrackControl(the_control, event->where, nil) != 0 )
  1262.                                 Close_ShowHelp( dialog);
  1263.                     }
  1264.                 }            
  1265.             }
  1266.             break;
  1267.         case keyDown :    
  1268.         case autoKey :
  1269.             charcode = event->message & charCodeMask;
  1270.             /*
  1271.                 There's no Cancel button, so we treat the OK button
  1272.                 the same as a Cancel button.
  1273.             */
  1274.             if ( (charcode == RETURN_CHAR) || (charcode == ENTER_CHAR) ||
  1275.                 (charcode == TILDE_CHAR) || (charcode == ESCAPE_CHAR) ||
  1276.                 ((charcode == '.') && (event->modifiers & cmdKey)) )
  1277.             {
  1278.                 ihit = c_OK;    /* OK */
  1279.                 Flash_button( dialog, ihit );
  1280.                 Close_ShowHelp( dialog);
  1281.             }
  1282.             else if ( (charcode == 'c') && (event->modifiers & cmdKey) )
  1283.             {
  1284.                 HiliteMenu(mEdit);
  1285.                 (void) ZeroScrap();
  1286.                 TECopy( gHelp_Text );
  1287.                 SystemEdit(3);
  1288.                 local_point = (**gHelp_Text).selPoint;
  1289.                 *(long *)&local_point = PinRect( &(**gHelp_Text).viewRect,
  1290.                     local_point );
  1291.                 cursor = TEGetOffset( local_point, gHelp_Text );
  1292.                 TESetSelect( (long)cursor, (long)cursor, gHelp_Text );
  1293.                 HiliteMenu(0);
  1294.                 Adjust_Menu(mEdit, 0, false);
  1295.                 Adjust_Menu(mEdit, iCopy, false);
  1296.                 DrawMenuBar();
  1297.             }
  1298.             break;
  1299.     } /* end switch */
  1300. }
  1301.  
  1302.  
  1303. /************************ Close_ShowHelp *******************************/
  1304.  
  1305. void        Close_ShowHelp( DialogPtr dptr )
  1306. {
  1307.     long        help_styl;
  1308.     long        the_info;
  1309.     long        help_popup;
  1310.     short        iType, which_pict;
  1311.     Handle        iHandle;
  1312.     Rect        iRect;
  1313.     
  1314.     GetDItem( dptr, c_save, &iType, &iHandle, &iRect);
  1315.     help_styl = GetCRefCon((ControlHandle)iHandle);
  1316.     Release_compressed_resource( (Handle) help_styl );
  1317.     ASSERT_SET_NIL( help_styl );
  1318.     
  1319.     DisposeRgn( ((help_ptr)dptr)->save_clip );
  1320.     ASSERT_SET_NIL( ((help_ptr)dptr)->save_clip );
  1321.     
  1322.     GetDItem(dptr, c_nullControl1, &iType, &iHandle, &iRect);
  1323.     the_info = GetCRefCon((ControlHandle)iHandle);
  1324.     ReleaseResource( (Handle) the_info );
  1325.     
  1326. #if USE_PICTS
  1327. #if COMPRESSION
  1328.     for (which_pict = 0; which_pict < ((help_ptr)dptr)->pict_count; ++which_pict)
  1329.     {
  1330.         Dispose_compressed_data( (Handle)
  1331.             ((help_ptr)dptr)->pict_data[which_pict].pict );
  1332.     }
  1333. #endif /* COMPRESSION */
  1334.     DisposPtr( (Ptr) ((help_ptr)dptr)->pict_data );
  1335.     ASSERT_SET_NIL( ((help_ptr)dptr)->pict_data );
  1336.     DisposHandle( (Handle) ((help_ptr) dptr)->high );
  1337.     ASSERT_SET_NIL( ((help_ptr) dptr)->high );
  1338. #endif /* USE_PICTS */
  1339.  
  1340.     TEDispose( gHelp_Text );
  1341.     ASSERT_SET_NIL( gHelp_Text );
  1342.     
  1343.     GetDItem( dptr, c_OK, &iType, &iHandle, &iRect);
  1344.     help_popup = GetCRefCon((ControlHandle)iHandle);
  1345.     
  1346.     DisposDialog( dptr );
  1347.     DisposeMenu( (MenuHandle)help_popup );
  1348.     
  1349.     gWindowsOpen--;
  1350.     if (! gWindowsOpen)
  1351.         Adjust_Menu(mFile, iClose, false);
  1352.     Adjust_Menu(mFile, iHelp, true);
  1353.     Adjust_Menu(mEdit, 0, false);
  1354.     DrawMenuBar();
  1355.     InitCursor();
  1356. }
  1357.  
  1358.  
  1359. /*********************** Adjust_EditMenu ****************************/ 
  1360.  
  1361. void        Adjust_EditMenu( Boolean do_activate, TEHandle the_text )
  1362. {
  1363.     MenuHandle    menu;
  1364.     
  1365.     menu = GetMHandle(mEdit);
  1366.     
  1367.     if (do_activate)
  1368.     {
  1369.         if ((**the_text).selStart != (**the_text).selEnd)
  1370.         {
  1371.             EnableItem(menu, 0);
  1372.             EnableItem(menu, iCopy);
  1373.         }
  1374.         else
  1375.         {
  1376.             DisableItem(menu, iCopy);
  1377.             DisableItem(menu, 0);
  1378.         }
  1379.         
  1380.         DisableItem(menu, iUndo);
  1381.         DisableItem(menu, iCut);
  1382.         DisableItem(menu, iPaste);
  1383.         DisableItem(menu, iSelectAll);
  1384.         DisableItem(menu, iClear);
  1385.         
  1386.     }
  1387.     else
  1388.         DisableItem(menu, 0);
  1389.         
  1390.     DrawMenuBar();
  1391. }
  1392.  
  1393.  
  1394. /************************* Do_ShowHelp_Copy ***************************/ 
  1395.  
  1396. void            Do_ShowHelp_Copy( DialogPtr showHelpDlg )
  1397. {
  1398.     EventRecord        event;
  1399.     
  1400.     event.what = keyDown;
  1401.     event.message = 'c';
  1402.     event.modifiers = event.modifiers | cmdKey;
  1403.     
  1404.     Handle_ShowHelp( &event, showHelpDlg );
  1405. }
  1406.  
  1407.  
  1408. /********************** Adjust_Menu ******************************/
  1409.  
  1410. void    Adjust_Menu( short menuID, short item, Boolean switchOn )
  1411. {
  1412.     MenuHandle    menu;
  1413.     
  1414.     menu = GetMHandle(menuID);
  1415.     if (menu)
  1416.     {
  1417.         if (switchOn)
  1418.             EnableItem(menu, item);
  1419.         else
  1420.             DisableItem(menu, item);
  1421.     }
  1422. }
  1423.  
  1424.  
  1425. /********************* Toggle_SH_ScrollBar ******************************/
  1426.  
  1427. static void        Toggle_SH_ScrollBar( DialogPtr dialog, short deactivate )
  1428. {
  1429.     ControlHandle    the_bar;
  1430.     
  1431.     the_bar    = ((help_ptr)dialog)->scrollbar;
  1432.     
  1433.     if (deactivate)
  1434.         HiliteControl(the_bar, kDisableControl);
  1435.     else
  1436.         HiliteControl(the_bar, kEnableControl);
  1437. }
  1438.  
  1439.  
  1440. /********************** Toggle_SH_Buttons ******************************/
  1441.  
  1442. static void        Toggle_SH_Buttons( DialogPtr dialog, short deactivate )
  1443. {
  1444.     ControlHandle    ok_button, save_button;
  1445.     short            iType;
  1446.     Rect            iRect;
  1447.     
  1448.     GetDItem(dialog, c_OK, &iType, &ok_button, &iRect);
  1449.     GetDItem(dialog, c_save, &iType, &save_button, &iRect);
  1450.     
  1451.     if (deactivate)
  1452.     {
  1453.         HiliteControl(ok_button, kDisableControl);
  1454.         HiliteControl(save_button, kDisableControl);
  1455.         HideDItem(dialog, KOutlinePICT);
  1456.     }
  1457.     else
  1458.     {
  1459.         HiliteControl(ok_button, kEnableControl);
  1460.         HiliteControl(save_button, kEnableControl);
  1461.         ShowDItem(dialog, KOutlinePICT);
  1462.     }
  1463. }